package com.xqboss.apps.service.guild;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.constant.Config;
import com.xqboss.apps.domain.guild.GuildMember;
import com.xqboss.apps.enums.consumer.ConsumerTeamRoleEnum;
import com.xqboss.apps.enums.guild.GuildExitStatusEnum;
import com.xqboss.apps.enums.guild.GuildExitTypeEnum;
import com.xqboss.apps.mapper.guild.GuildMemberMapper;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.LocalDateUtils;
import com.xqboss.framework.web.service.TokenService;
import com.xqboss.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Optional;

/**
 * 公会成员接口
 *
 * @author wangcong
 * @date 2023-11-01
 */
@Service
public class GuildMemberService extends ServiceImpl<GuildMemberMapper, GuildMember> {


    @Autowired
    private ISysConfigService sysConfigService;//系统配置参数


    /**
     * 判断用户是否已经有加入的队伍了
     *
     * @param userId 用户
     * @return true-是
     */
    public Boolean getIsJoinGuild(Long userId) {
        Optional.ofNullable(userId).orElseThrow(()->new ServiceException("用户id不能为空！"));
        Long count = this.lambdaQuery().eq(GuildMember::getUserId, userId).count();
        return count!=0;
    }

    /**
     * 获取用户已加入公会的成员信息
     *
     * @param userId 用户
     * @return 成员信息
     */
    public GuildMember getGuildMemberInfo(Long userId) {
        Optional.ofNullable(userId).orElseThrow(()->new ServiceException("用户id不能为空！"));
        GuildMember member = this.lambdaQuery().eq(GuildMember::getUserId, userId).one();
        return Optional.ofNullable(member).orElse(null);
    }

    /**
     * 创建成员（会长或会员）
     *
     * @param guildId 公会id
     * @param userId 加入公会的用户id
     * @param role 角色
     * @param inviteUserId 邀请人用户id
     * @param isConsume 进入公会是否消耗材料（true-消耗）
     */
    @Transactional(rollbackFor = Exception.class)
    public void createMember(Long guildId,Long userId,ConsumerTeamRoleEnum role,Long inviteUserId,Boolean isConsume,Boolean isCreateGuild) {
        Optional.ofNullable(guildId).orElseThrow(()->new ServiceException("公会id不能为空！"));
        Optional.ofNullable(userId).orElseThrow(()->new ServiceException("用户id不能为空！"));
        Optional.ofNullable(role).orElseThrow(()->new ServiceException("公会成员角色不能为空！"));
        boolean finalIsConsume = Boolean.FALSE;
        if (isCreateGuild) {
            //创建公会
            finalIsConsume = isConsume;
        }else {
            // 获取审核的用户上一次退出公会的状态，如果是非主动退出公会，那么字段 isConsume设置为true，表示为消耗了材料
            boolean isExitActiveUn =  this.getLastExitGuildInfo(userId) == GuildExitStatusEnum.EXIT_ACTIVE_UN ;
            //加入公会
            finalIsConsume = isExitActiveUn || isConsume;// 非主动退出也记为消耗材料
        }
        //创建公会成员
        GuildMember guildMember = GuildMember.builder()
                .guildId(guildId)
                .userId(userId)
                .role(role)
                .joinTime(LocalDateUtils.getCurrentLocalDateTime())
                .inviteUserId(inviteUserId)
                .isConsume(finalIsConsume)
                .build();
        //新增会长
        boolean save = this.save(guildMember);
        //验证
        Assert.isTrue(save, () -> new ServiceException(String.format("用户%s创建成员失败！", userId)));
    }

    /**
     * 判断用户上一次退出队伍时的状态(前提：该成员已退出了公会)
     *
     * 主动退出，受24小时冷却时间限制
     *
     * @param userId 用户id
     * @return 1 -主动退出 ；2 - 非主动退出 ；3-第一次加入公会
     */
    public GuildExitStatusEnum getLastExitGuildInfo(Long userId) {
        Optional.ofNullable(userId).orElseThrow(()->new ServiceException("用户id不能为空！"));
        //获取用户上一次退出队伍时的成员信息
        GuildMember member = this.getBaseMapper().getLastExitGuildInfo(userId);
        //如果为null，说明成员还没有退出公会，或还没有加入过公会
        if (member==null) return GuildExitStatusEnum.FIRST_JOIN_GUILD;
        //如果不为null，说明成员退出了公会，那么要是主动退出还是非主动退出，主动退出不冷却
        if (member.getExitStatus() == GuildExitStatusEnum.EXIT_ACTIVE) {
            Integer coolHours = this.sysConfigService.getValue(Config.Sys.Guild.主动退出公会冷却时间);
            boolean isCool = ChronoUnit.SECONDS.between(member.getExitTime().plusHours(coolHours), LocalDateTime.now()) < 0;
            Assert.isFalse(isCool,()->new ServiceException(String.format("冷却中，主动退出公会%s小时后才能再次加入~",coolHours)));
        }
        //如果为非主动退出，判断是否是被管理员踢出的，如果是，则判断进公会前是否消耗了材料，若没有消耗材料，则判定该次用户被踢出为主动退出
        if (member.getExitStatus() == GuildExitStatusEnum.EXIT_ACTIVE_UN && member.getExitType()==GuildExitTypeEnum.KICKED && !member.getIsConsume()) {
            return GuildExitStatusEnum.EXIT_ACTIVE;
        }
        return member.getExitStatus();
    }

    /**
     * 退出公会
     *
     * @param guildId 公会id
     * @param userId 用户id
     * @param exitStatus 退出状态 （1-主动退出，2-非主动退出）
     * @param exitType 退出类型（1-主动退出，2-会长解散公会，3-被踢出，4-被拒绝，5-后台解散公会）
     */
    @Transactional(rollbackFor = Exception.class)
    public void exitGuild(Long guildId,Long userId, GuildExitStatusEnum exitStatus, GuildExitTypeEnum exitType) {
        Optional.ofNullable(guildId).orElseThrow(()->new ServiceException("公会id不能为空！"));
        Optional.ofNullable(userId).orElseThrow(()->new ServiceException("用户id不能为空！"));
        Optional.ofNullable(exitStatus).orElseThrow(()->new ServiceException("退出状态不能为空！"));
        Optional.ofNullable(exitType).orElseThrow(()->new ServiceException("退出类型不能为空！"));
        // 更新退出时间，状态和类型
        boolean update = this.lambdaUpdate()
                .set(GuildMember::getExitTime, LocalDateUtils.getCurrentLocalDateTime())
                .set(GuildMember::getExitStatus, exitStatus)
                .set(GuildMember::getExitType, exitType)
                .set(GuildMember::getDelFlag, Boolean.TRUE)
                .eq(GuildMember::getUserId, userId)
                .eq(GuildMember::getGuildId,guildId)
                .eq(GuildMember::getDelFlag, Boolean.FALSE)
                .update();
        Assert.isTrue(update,()->new ServiceException("退出公会失败~"));
    }
}
